
// Copyright (C) 2009 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.IO;

namespace Derm.BindGen
{
	class EnumClassFactory :
		PartialClassFactory
	{
		#region Constructors & Destructor
		
		public EnumClassFactory(string ns, string cName, IDictionary<string,Enum> cEnums) :
			base(ns, cName)
		{
			mEnums = new SortedList<string, Enum>(cEnums);
		}

		/// <summary>
		/// Enums to define.
		/// </summary>
		private IDictionary<string,Enum> mEnums;
		
		#endregion

		public override void WriteAssembly(string path, SourceExt exts)
		{
			if ((exts & SourceExt.ARB) != 0)
				WriteAssemblyImplementation(path+ClassName+"EnumARB.cs", WriteArbClassImplementation);
			if ((exts & SourceExt.EXT) != 0)
				WriteAssemblyImplementation(path+ClassName+"EnumEXT.cs", WriteExtClassImplementation);
			if ((exts & SourceExt.ATI) != 0)
				WriteAssemblyImplementation(path+ClassName+"EnumATI.cs", WriteAtiClassImplementation);
			if ((exts & SourceExt.NV) != 0)
				WriteAssemblyImplementation(path+ClassName+"EnumNV.cs", WriteNvClassImplementation);
			
			WriteAssemblyImplementation(path+ClassName+"Enum.cs", WriteBaseClassImplementation);
		}

		protected void WriteBaseClassImplementation(StreamWriter sw)
		{
			WriteExtensionClassImplementation(sw, null, sExcludeExtFilter);
		}

		protected void WriteArbClassImplementation(StreamWriter sw)
		{
			WriteExtensionClassImplementation(sw, new string[] { "ARB" }, sExcludeExtFilter);
		}

		protected void WriteExtClassImplementation(StreamWriter sw)
		{
			WriteExtensionClassImplementation(sw, new string[] { "EXT" }, sExcludeExtFilter);
		}

		protected void WriteAtiClassImplementation(StreamWriter sw)
		{
			WriteExtensionClassImplementation(sw, new string[] { "ATI" }, sExcludeExtFilter);
		}

		protected void WriteNvClassImplementation(StreamWriter sw)
		{
			WriteExtensionClassImplementation(sw, new string[] { "NV", "GL_NV" }, sExcludeExtFilter);
		}

		protected void WriteExtensionClassImplementation(StreamWriter sw, string[] incPrefix, string[] exPrefix)
		{
			LinkedList<string> mRemovedKeys = new LinkedList<string>();

			// Write enumerations
			foreach (Enum eItem in mEnums.Values) {
				if (eItem.ValuesCount > 0) {
					if (exPrefix != null) {
						bool skip = false;

						foreach (string p in exPrefix)
							if ((eItem.Name.StartsWith(p) == true) || (eItem.Name.EndsWith(p))) {
								skip = true;
								break;
							}

						if (skip == true)
							continue;
					}
					if (incPrefix != null) {
						foreach (string p in incPrefix) {
							if ((eItem.Name.StartsWith(p) == true) || (eItem.Name.EndsWith(p))) {
								WriteEnumDefinition(sw, eItem);
								mRemovedKeys.AddLast(eItem.Name);
							}
						}
					} else {
						WriteEnumDefinition(sw, eItem);
						mRemovedKeys.AddLast(eItem.Name);
					}
				}
			}

			/* Remove inserted items */
			foreach (string k in mRemovedKeys)
				mEnums.Remove(k);
		}

		private void WriteEnumDefinition(StreamWriter sw, Enum eItem)
		{
			// Mark enum begin
			sw.WriteLine("		#region " + eItem.Name);
			sw.WriteLine();
			// Define enumeration values
			foreach (Enum.Value v in eItem.Values) {
				string doc = v.GetEnumerationDocumentation();

				if (doc != null) {
					sw.WriteLine("		/// <summary>");
					sw.WriteLine("		/// "+doc);
					sw.WriteLine("		/// </summary>");
					if (v.IsDeprecated == true) {
						sw.WriteLine("		/// <remarks>");
						sw.WriteLine("		/// This enumeration value is DEPRECATED.");
						foreach (string alias in v.NameAliases)
							sw.WriteLine("		/// This enumeration value is an alias for symbol {0}.", alias);
						sw.WriteLine("		/// </remarks>");
					}
				}
				sw.WriteLine("		"+v.GetEnumerationDeclaration());
			}
			sw.WriteLine();
			// Mark enum end
			sw.WriteLine("		#endregion");
			sw.WriteLine();
		}

		private static readonly string[] sExcludeExtFilter = new string[] {
			"3DFX",
			"AMD",
			"APPLE",
			"HP",
			"IBM",
			"IMG",
			"INGR",
			"INTEL",
			"MESA", "MESAX",
			"OES",
			"OML",
			"PGI",
			"QCOM",
			"REND",
			"S3",
			"SGI", "SGIS", "SGIX",
			"SUN", "SUNX",
			"WIN"
		};
	}
}
